Skip to content

chore: release 2.3.1#608

Open
piotr-iohk wants to merge 6 commits into
masterfrom
ovi/release-2.3.0
Open

chore: release 2.3.1#608
piotr-iohk wants to merge 6 commits into
masterfrom
ovi/release-2.3.0

Conversation

@piotr-iohk

@piotr-iohk piotr-iohk commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Hotfix release 2.3.1 (build 192) on top of v2.3.0.

Description

  • Routes LNURL-pay invoice fetching through bitkit-core with full LnurlPayData validation
  • Handles core invoice validation errors with a neutral payment-canceled message
  • bitkit-core 0.1.75 (WoS amountless LNURL-pay fix)
  • CURRENT_PROJECT_VERSION: 191 → 192 (build-only bump for TestFlight; marketing version unchanged)
  • MARKETING_VERSION: 2.3.0 → 2.3.1

Release

  • Tag: v2.3.1 (draft)
  • Branch: ovi/release-2.3.0
  • TestFlight upload pending (manual Xcode archive, build 192)

Screenshot / Video

N/A

QA Notes

  • Staging regtest: normal LN sends with QuickPay on/off
  • CI @lnurl_1 green with matching e2e branch (fix/lnurl-pay @ d00494d)
  • Stacker News / Blitz probe targets: external/WAF — not a regression (fails on 2.3.0 too)

ovitrif and others added 3 commits June 26, 2026 05:04
fix: use core LNURL-pay validation
Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown

Greptile Summary

This hotfix routes LNURL-pay invoice fetching through bitkit-core (bumped 0.1.64 → 0.1.74), gaining full LnurlPayData validation (amount, metadata) and mapping known validation errors to a neutral LnurlPayInvoiceMismatchError message. Version is bumped to 2.3.1 (build 191) across all targets.

  • Core change (Lnurl.swift): fetchLnurlInvoice now delegates to getLnurlInvoiceForPayData instead of building its own HTTP request; mapLnurlPayInvoiceError translates InvalidAmount, AmountMismatch, and MetadataMismatch into a user-friendly cancellation message.
  • Call sites (LnurlPayConfirm.swift, SendQuickpay.swift): updated to pass the full LnurlPayData object instead of just the callback URL string.
  • TrezorViewModel: adds WatcherError handling to match a new variant in the updated core library.

Confidence Score: 3/5

The core LNURL validation logic is solid, but the QuickPay flow silently discards the new validation errors, leaving users stranded on the loading screen without any feedback when an invoice fails validation.

The central improvement — delegating invoice fetch and validation to bitkit-core — is clean and the error mapping in Lnurl.swift is correct. The problem is in SendQuickpay.swift: validation errors thrown by fetchLnurlInvoice propagate out of performPayment() and are silently discarded by the unstructured Task in onAppear. This is the exact scenario the PR is meant to improve (invalid invoices from LNURL servers), so the failure to surface those errors in the QuickPay path undermines the intent of the fix.

SendQuickpay.swift needs the fetch-error path handled before the inner do-catch; LnurlPayConfirm.swift should consistently catch fetchLnurlInvoice errors alongside send errors.

Important Files Changed

Filename Overview
Bitkit/Utilities/Lnurl.swift Replaces ad-hoc HTTP invoice fetch with bitkit-core's getLnurlInvoiceForPayData; adds LnurlPayInvoiceMismatchError and mapLnurlPayInvoiceError to translate validation failures into a neutral user-facing message. Logic is sound.
Bitkit/Views/Wallets/Send/SendQuickpay.swift Updated call site passes LnurlPayData instead of callbackUrl. The unstructured Task in onAppear swallows any error thrown by fetchLnurlInvoice before the inner do-catch, leaving the user stuck on the loading screen when core validation fails.
Bitkit/Views/Wallets/Send/LnurlPayConfirm.swift Updated call site passes LnurlPayData. fetchLnurlInvoice errors propagate outside performPayment's inner do-catch, so their toast+navigation path relies on SwipeButton handling them gracefully.
Bitkit/ViewModels/Trezor/TrezorViewModel.swift Adds WatcherError case to the error description switch to match a new variant introduced in bitkit-core 0.1.74. Straightforward and correct.
Bitkit.xcodeproj/project.pbxproj Bumps CURRENT_PROJECT_VERSION to 191 and MARKETING_VERSION to 2.3.1 across all six build targets (Debug/Release x app, widget, notification). Consistent and correct.
Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved bitkit-core pinned from 0.1.64 (a7577cc) to 0.1.74 (201e37b). Lock file updated to match the project.pbxproj requirement.
CHANGELOG.md Adds 2.3.1 release entry and updates the Unreleased comparison link. Follows Keep a Changelog conventions correctly.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as SendQuickpay / LnurlPayConfirm
    participant Helper as LnurlHelper
    participant Core as BitkitCore
    participant Server as LNURL Server

    UI->>Helper: fetchLnurlInvoice(data, amountMsats)
    Helper->>Core: getLnurlInvoiceForPayData(data, amountMsats)
    Core->>Server: "HTTP GET callback?amount=..."
    Server-->>Core: bolt11 invoice
    Core->>Core: Validate amount / metadata
    alt Validation passes
        Core-->>Helper: invoice string
        Helper-->>UI: invoice string
        UI->>UI: sendWithTimeout(bolt11)
    else Validation fails
        Core-->>Helper: throws LnurlError
        Helper->>Helper: mapLnurlPayInvoiceError
        Helper-->>UI: throws LnurlPayInvoiceMismatchError
        note over UI: SendQuickpay: swallowed by Task, no UX feedback
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as SendQuickpay / LnurlPayConfirm
    participant Helper as LnurlHelper
    participant Core as BitkitCore
    participant Server as LNURL Server

    UI->>Helper: fetchLnurlInvoice(data, amountMsats)
    Helper->>Core: getLnurlInvoiceForPayData(data, amountMsats)
    Core->>Server: "HTTP GET callback?amount=..."
    Server-->>Core: bolt11 invoice
    Core->>Core: Validate amount / metadata
    alt Validation passes
        Core-->>Helper: invoice string
        Helper-->>UI: invoice string
        UI->>UI: sendWithTimeout(bolt11)
    else Validation fails
        Core-->>Helper: throws LnurlError
        Helper->>Helper: mapLnurlPayInvoiceError
        Helper-->>UI: throws LnurlPayInvoiceMismatchError
        note over UI: SendQuickpay: swallowed by Task, no UX feedback
    end
Loading

Comments Outside Diff (1)

  1. Bitkit/Views/Wallets/Send/SendQuickpay.swift, line 36-39 (link)

    P1 Unstructured Task silently swallows LNURL validation errors

    Task { try await performPayment() } drops any error thrown before the inner do-catch is reached. With this PR, fetchLnurlInvoice now performs amount/metadata validation via core and can throw LnurlPayInvoiceMismatchError; that error propagates out of performPayment() but is silently discarded by the unstructured Task. The user is left stranded on the QuickPay loading spinner with no feedback. The network and parse errors that existed before this PR had the same fate, but this PR makes the path far more likely to be hit (e.g. any server returning an amount that doesn't match). Wrapping the fetchLnurlInvoice call in a do-catch that mirrors the inner error handler (toast + navigate to .failure) would close the gap.

Reviews (1): Last reviewed commit: "chore: version 2.3.1" | Re-trigger Greptile

Comment on lines 196 to 200
let bolt11 = try await LnurlHelper.fetchLnurlInvoice(
callbackUrl: lnurlPayData.callback,
data: lnurlPayData,
amountMsats: amountMsats,
comment: comment.isEmpty ? nil : comment
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Invoice-fetch errors escape the inner catch block

fetchLnurlInvoice is called before the do-catch that toasts the error and navigates to .failure. If core validation throws (e.g. AmountMismatch), the error propagates out of performPayment() to SwipeButton's closure; whether SwipeButton surfaces it to the user is not guaranteed. The inner do-catch already handles send failures with a toast + failure navigation — fetch failures should be treated the same way for consistent UX.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d700f60075

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +51 to 52
data: lnurlPayData,
amountMsats: lnurlPayData.callbackAmountMsats()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle LNURL validation failures in QuickPay

When a fixed-amount LNURL-pay endpoint returns an invoice that fails the new core amount/metadata validation, this call now throws before performPayment() reaches the do/catch that navigates to the failure state. In QuickPay it is invoked from Task { try await performPayment() } without any outer catch, so the payment is correctly cancelled but the user remains on the loader indefinitely instead of seeing the failure path; wrap the fetch/parse step in the existing error handling or catch at the task boundary.

Useful? React with 👍 / 👎.

@piotr-iohk piotr-iohk self-assigned this Jun 26, 2026
@piotr-iohk piotr-iohk requested a review from ovitrif June 26, 2026 12:03
@ovitrif ovitrif self-assigned this Jun 26, 2026
ovitrif and others added 3 commits June 26, 2026 16:45
Collect hotfix changelog for #610 and bump build for TestFlight upload.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants